package org.blankie.util;

import java.io.Serializable;
import java.util.Collection;

import org.blankie.lang.Validate;

public class OrganizationSynchronizedWrapper<O extends Organized,
                                             N extends Organized,
                                             L extends Organized>
        implements OrganizationManager<O, N, L>, Serializable {

    private static final long serialVersionUID = 0L;

    private final OrganizationManager<O, N, L> delegate;

    public OrganizationSynchronizedWrapper(OrganizationManager<O, N, L> delegate) {
        Validate.parameterNotNull("delegate", delegate);
        this.delegate = delegate;
    }

    public Collection<L> getLeaves(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.getLeaves(managed);
        }
    }

    public void getLeaves(Organized managed, Collection<? super L> into) {
        Validate.parameterNotNull("managed, into", managed, into);
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            delegate.getLeaves(managed, into);
        }
    }

    public Collection<N> getNodes(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.getNodes(managed);
        }
    }

    public void getNodes(Organized managed, Collection<? super N> into) {
        Validate.parameterNotNull("managed, into", managed, into);
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            delegate.getNodes(managed, into);
        }
    }

    public O getOrganization(Organized managed) {
        return delegate.getOrganization(managed);
    }

    public N getParent(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.getParent(managed);
        }
    }

    public N getRoot(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.getRoot(managed);
        }
    }

    public boolean hasLeaves(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.hasLeaves(managed);
        }
    }

    public boolean hasNodes(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.hasNodes(managed);
        }
    }

    public boolean isLeaf(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.isLeaf(managed);
        }
    }

    public boolean isNode(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.isNode(managed);
        }
    }

    public boolean isOrganization(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.isOrganization(managed);
        }
    }

    public boolean isRoot(Organized managed) {
        Validate.notNull("managed.manager", managed);

        Organized organization = managed.getManager().getOrganization(managed);
        Validate.notNull(organization != null);

        synchronized (organization) {
            return delegate.isRoot(managed);
        }
    }

}
